<?php
    namespace app\admin\controller;
    use app\admin\controller\Base;
    use think\Db;
    class Workflowajax extends Base {
        public $now_user;
        /**
        *
        * 详情页 details
        * 1,假设是当前用户，郝宇
        * 2，假设是上司，吴总监
        * 3，假设是总经理，廖总
        * @return array|void
        */
        public function _initialize() {
            $this->now_user = session('id');
            //        $this->now_user = 1;  //全局配置替换登陆ID 只替换了ID，其他没有替换
        }
        /*********************************************************************模版生产**********************************************************************/
        /**
        * 获取审批流模板列表
        */
        public function get_flow_list() {
            $list = Db::name('wf_flow') ->where(['isdelete'=>0]) ->field('id,name,total,state') ->select();
            $lists = array();
            foreach($list as $key=>$val) {
                foreach($val as $k=>$v) {
                    $lists[$key][$k] = $v;
                }
            }
            $data = array('code'=>'200', 'msg'=>'请求成功', 'count'=>count($lists), 'data'=>$lists,);
            return $data;
        }
        /**
        * 创建审批流模板  name|功能名（汉字） controller|控制器（代码）table_name|表名（代码）
        */
        public function add_flow() {
            if (request() ->isAjax()) {
                $type = input('type');
                $param = request() ->post();
                $where = $param;
                $where['is_form_extend'] = $type;
                $where['isdelete'] = $param['isdelete'] = 0;
                $field = array();
                Db::startTrans();
                try {
                    $res = Db::name('wf_flow') ->insert($where);
                    if ($type == 1 && $res) {
                        $flow_id = Db::name('wf_flow') ->getLastInsID();
                        $table_names = array('sys_user');
                        array_push($table_names, $where['table_name']);
                        $fields = $this->get_fields($table_names, $flow_id);
                        $fs = Db::name('wf_form_field') ->insertAll($fields);
                        if ($fs) {
                            $msg = '添加成功';
                            $code = 200;
                        } else {
                            $msg = '表单字段创建失败';
                            $code = -2;
                        }
                    } elseif ($type == 0 && $res) {
                        $msg = '添加成功';
                        $code = 200;
                    } else {
                        $msg = '添加失败';
                        $code = -1;
                    }
                    // 提交事务
                    Db::commit();
                }
                catch(\Exception $e) {
                    //                 回滚事务
                    $msg = '添加失败(完全回滚)';
                    $code = -3;
                    Db::rollback();
                }
                return json($msg, $code);
            }
        }
        /**
        * 创建审批流模板  name|功能名（汉字） controller|控制器（代码）table_name|表名（代码）
        */
        public function edit_flow() {
            if (request() ->isAjax()) {
                $type = input('type');
                $param = request() ->post();
                $flow_id = $param['id'];
                unset($param['id']);
                $field = array();
                Db::startTrans();
                try {
                    $res = Db::name('wf_flow') ->where(['id'=>$flow_id]) ->update($param);
                    if ($type == 1 && $res) {
                        $this->match_updata($flow_id);
                        $msg = '修改成功';
                        $code = 200;
                    } elseif ($type == 0 && $res) {
                        $msg = '添加成功';
                        $code = 200;
                    } else {
                        $msg = '添加失败';
                        $code = -1;
                    }
                    // 提交事务
                    Db::commit();
                }
                catch(\Exception $e) {
                    //                 回滚事务
                    $msg = '添加失败(完全回滚)';
                    $code = -3;
                    Db::rollback();
                }
                return json($msg, $code);
            }
        }
        /**
        * 增量修改字段
        * @param string $flow_id 模板ID
        */
        public function match_updata($flow_id) {
            //获取已有信息--含绑定表名
            $flow = Db::name('wf_flow') ->find($flow_id);
            //查询原始字段字段
            $original_list = Db::name('wf_form_field') ->where(['flow_id'=>$flow_id]) ->select();
            //查询新的字段
            $table_names = array('sys_user');
            array_push($table_names, $flow['table_name']);
            $new_list = $this->get_fields($table_names, $flow_id);
            //不变的字段
            $unchanged = $this->get_field_un($original_list, $new_list);
            //新增字段
            $add = $this->get_field_action($new_list, $unchanged);
            //删除字段
            $del = $this->get_field_action($original_list, $unchanged); //需要删除ID
            if (!empty($del)) {
                foreach($del as $k=>$v) {
                    Db::name('wf_form_field') ->where(['id'=>$v['id']]) ->update(['isdelete'=>0]);
                }
            }
            if (!empty($add)) {
                foreach($add as $k=>$v) {
                    $field_id = Db::name('wf_form_field') ->where(['field_name'=>$v['field_name'], 'source_table'=>$v['source_table'], 'isdelete'=>1]) ->find() ['id'];
                    if ($field_id) { //有历史文件修改状态
                        Db::name('wf_from_field') ->where(['id'=>$field_id]) ->update(['isdelete'=>0]);
                    } else { //否则真的新增
                        Db::name('wf_from_field') ->where(['id'=>$field_id]) ->insert($v);
                    }
                }
            }
        }
        /**
        * 不变的字段
        * @param array $old 旧的所有字段
        * @param array $new 新的所有字段
        * @return array $unchanged 不变的字段
        */
        public function get_field_un($old, $new) {
            $unchanged = array();
            foreach($old as $key=>$val) {
                foreach($new as $k=>$v) {
                    if ($v['field_name'] == $val['field_name'] && $v['source_table'] == $val['source_table']) {
                        array_push($unchanged, $old[$key]);
                    }
                }
            }
            return $unchanged;
        }
        /**
        * 获取需要新增的字段
        * @param array $array 需要对比的字段
        * @param array $un 参照字段
        * @return array $array 变动字段
        */
        public function demo($array, $un) {
            foreach($array as $key=>$val) {
                foreach($un as $k=>$v) {
                    if ($val['field_name'] == $v['field_name'] && $val['source_table'] == $v['source_table']) {
                        unset($array[$key]);
                    }
                }
            }
            return $array;
        }
        /**
        * 获取外接表单字段
        * @param array $table_name  表名数组
        * @param bool $flow_id   模板ID
        * @return mixed|string
        */
        public function get_fields($table_name, $flow_id) {
            $data = array();
            $num = 0;
            foreach($table_name as $key=>$val) {
                $original = $this->get_db_column_comment($val);
                foreach($original as $k=>$v) {
                    if (empty($v['comment'])) {
                        $data[$num]['name'] = $v['field'];
                    } else {
                        $data[$num]['name'] = $v['comment'];  //字段注释名
                    }
                    $data[$num]['field_name'] = $v['field'];  //字段代码
                    $data[$num]['source_table'] = $val;  //来源表单
                    $data[$num]['field_type'] = 1;
                    $data[$num]['flow_id'] = $flow_id;
                    $data[$num]['isdelete'] = 0;
                    $num++;
                }
            }
            return $data;
        }
        /**
        * 根据表名获取表字段和描述
        * @param string $table_name
        * @param bool $field
        * @param string $table_schema
        * @return mixed|string
        */
        function get_db_column_comment($table_name = '', $field = true, $table_schema = '') {
            // 接收参数
            $database = config('database');
            $table_schema = empty($table_schema) ? $database['database'] : $table_schema;
            $table_name = $database['prefix'].$table_name;
            // 缓存名称
            $fieldName = $field === true ? 'allField' : $field;
            $cacheKeyName = 'db_'.$table_schema.'_'.$table_name.'_'.$fieldName;
            // 处理参数
            $param = [$table_name, $table_schema];
            // 字段
            $columeName = '';
            if ($field !== true) {
                $param[] = $field;
                $columeName = "AND COLUMN_NAME = ?";
            }
            // 查询结果
            $result = Db::query("SELECT COLUMN_NAME as field,column_comment as comment FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = ? AND table_schema = ? $columeName", $param);
            if (empty($result) && $field !== true) {
                return $table_name.'表'.$field.'字段不存在';
            }
            $data = $result;
            return count($data) == 1 ? reset($data) : $data;
        }
        /**
        * 删除流程模板
        * @throws \think\Exception
        * @throws \think\exception\PDOException
        */
        public function delete_flow() {
            if (request() ->isAjax()) {
                Db::startTrans();
                //要删除的节点ID
                $flow_id = input('id');
                $flow = Db::name('wf_flow') ->find('$flow_id');
                $bool = "";
                try {
                    //删除相关节点数据
                    Db::name('wf_process') ->where('flow_id', 'eq', $flow_id) ->update(['isdelete'=>1]);
                    //删除对应表单字段
                    if ($flow['is_form_extend'] == 1) {
                        Db::name('wf_form_field') ->where('form_extend_id', 'eq', $flow['form_extend_id']) ->update(['isdelete'=>1]);
                    } else {
                        Db::name('wf_form_field') ->where('flow_id', 'eq', $flow_id) ->update(['isdelete'=>1]);
                    }
                    //删除审批流模版
                    Db::name('wf_flow') ->where('id', 'eq', $flow_id) ->update(['isdelete'=>1]);
                    Db::commit();
                    $bool = true;
                }
                catch(\Exception $e) {
                    Db::rollback();
                    $bool = false;
                }
                if ($bool) {
                    return $this->success('删除成功');
                } else {
                    return $this->error('删除失败');
                }
            }
        }
        /**
        * 删除审批流
        */
        public function delete_workflow() {
            if (request() ->isAjax()) {
                Db::startTrans();
                //要删除的节点ID
                $workflow_id = input('id');
                $bool = "";
                try {
                    //删除对应操作表
                    Db::name('wf_examine') ->where('workflow_id', 'eq', $workflow_id) ->update(['isdelete'=>1]);
                    //删除相关节点数据
                    Db::name('wf_workprocess') ->where('workflow_id', 'eq', $workflow_id) ->update(['isdelete'=>1]);
                    //删除审批流模版
                    Db::name('wf_workflow') ->where('id', 'eq', $workflow_id) ->update(['isdelete'=>1]);
                    Db::commit();
                    $bool = true;
                }
                catch(\Exception $e) {
                    Db::rollback();
                    $bool = false;
                }
                if ($bool) {
                    return $this->success('删除成功');
                } else {
                    return $this->error('删除失败');
                }
            }
        }
        /**
        * 添加节点 paste
        */
        public function add_process() {
            if (request() ->isAjax()) {
                $where = array();
                $input = input();
                if ($input['type'] == 'paste') {
                    $process_id = isset($input['process_id']) ? $input['process_id'] : '';
                    $attr = Db::name('wf_process') ->field('flow_id,
                    process_name,
                    icon,
                    style,
                    auto_person,
                    auto_unlock,
                    auto_sponsor_uids,
                    auto_respon_uids,
                    auto_role_ids,
                    range_user_ids,
                    range_dept_ids,
                    range_role_ids,
                    con_sign,
                    con_sign_vsb,
                    con_sign_back,
                    write,
                    secret') ->find($process_id); //复制节点通用属性
                    //处理style中的坐标到刚刚粘贴的坐标
                    $array = json_decode($attr['style'], true);
                    $array['top'] = $input['top'];
                    $array['left'] = $input['left'];
                    $attr['style'] = json_encode($array);   //样式数据
                    $res = Db::name('wf_process') ->insert($attr);
                    if ($res) {
                        return $this->success('创建成功', '', $res);
                    }
                }
                $where['style'] = json_encode(array("top"=>isset($input['top']) ? $input['top'] : rand(10, 999) .'px', "left"=>isset($input['left']) ? $input['left'] : rand(10, 999) .'px', "width"=>"200px", "height"=>"50px"));
                $where['flow_id'] = input('flow_id');
                $where['isdelete'] = 0;
                //写入节点表
                $res = Db::name('wf_process') ->insert($where);
                $newId = Db::name('wf_process') ->getLastInsID();
                //回写审核节点数量
                Db::name('wf_flow') ->where('id', input("flow_id")) ->update(['total'=>(count(Db::name('wf_process') ->where('flow_id', $where['flow_id']) ->select()) -1) ]);
                //添加子节点时，回写上游节点链接关系
                if ($input['type'] == 'addson') {
                    $process_id = isset($input['process_id']) ? $input['process_id'] : '';
                    $process_to = explode(',', Db::name('wf_process') ->field('process_to') ->find($process_id) ['process_to']);
                    array_push($process_to, $newId);
                    Db::name('wf_process') ->where('id', $process_id) ->update(['process_to'=>implode(',', $process_to) ]);
                }
                if ($res) {
                    return $this->success('创建成功', '', $res);
                }
            }
        }
        /**
        * 删除节点
        */
        public function delete_process() {
            if (request() ->isAjax()) {
                //要删除的节点ID
                $process_id = input('process_id');
                //删除上游关系
                $process_up = $this->get_up($process_id);
                foreach($process_up as $k=>$v) {
                    $process_to = explode(',', $v['process_to']);
                    $param['process_to'] = implode(',', array_diff($process_to, [$process_id]));
                    Db::name('wf_process') ->where('id', 'eq', $v['id']) ->update($param);
                }
                $res = Db::name('wf_process') ->where(['id'=>$process_id]) ->update(['isdelete'=>1]);
                if ($res === false) {
                    return $this->error('删除失败');
                } else {
                    return $this->success('删除成功');
                }
            }
        }
        /**
        *获取工作流模板相关节点信息
        */
        public function get_process() {
            $id = input('id');
            $data = Db::name('wf_flow') ->where('id', $id) ->field('id as flow_id,total') ->find();
            $list = Db::name('wf_process') ->where(['flow_id'=>$id, 'isdelete'=>0]) ->field('id,flow_id,process_to,icon,process_name,style') ->select();
            $lists = array();
            foreach($list as $key=>$val) {
                foreach($val as $k=>$v) {
                    $lists[$val['id']][$k] = $v;
                }
            }
            $data['list'] = (object)$lists;
            return $this->success('', '', $data);
        }
        /**
        *保存审批流可视化链接状态
        */
        public function save_link() {
            $put = file_get_contents('php://input');  //接收多维json
            $param = json_decode($put);
            $num = 0;
            foreach($param as $key=>$val) {
                $metadata = $this->object2array($val);   //获取单条元数据
                //查询节点是否为开始节点
                foreach($metadata['process_to'] as $k=>$v) {
                    $type = Db::name('wf_process') ->field('process_type') ->find($v) ['process_type'];
                    if ($type == 'is_start') {
                        unset($metadata['process_to'][$k]);
                    }
                }
                $where['process_to'] = implode(',', $metadata['process_to']);  //处理连线信息
                //处理style信息
                $style = Db::name('wf_process') ->field('style') ->find($key) ['style'];
                $where['style'] = $this->handle_json($metadata, $style);  //替换json
                $res = Db::name('wf_process') ->where('id', 'eq', $key) ->update($where);
                if ($res == 1 || $res == 0) {
                    $num++;
                }
            }
            if ($num == count((array)$param)) {
                return $this->success('保存成功');
            } else {
                $number = count((array)$param) -$num;
                return $this->error('失败了'.$number.'条');
            }
        }
        /**
        * 设为第一步
        */
        public function set_one() {
            if (request() ->isAjax()) {
                $process_id = input('process_id');
                $param['process_type'] = 'is_start';
                //清除上游节点关系
                $process_up = $this->get_up($process_id);
                foreach($process_up as $k=>$v) {
                    $process_to = explode(',', $v['process_to']);
                    $param2['process_to'] = implode(',', array_diff($process_to, [$process_id]));
                    Db::name('wf_process') ->where('id', 'eq', $v['id']) ->update($param2);
                }
                //设置当前节点为第一步
                $res = Db::name('wf_process') ->where('id', 'eq', $process_id) ->update($param);
                if ($res == 1 || $res == 0) {
                    return $this->success('设置成功');
                }
                $this->success('设置失败');
            }
        }
        /**
        * 获取当前流程的表单字段信息
        */
        public function get_field() {
            if (request() ->isAjax()) {
                $flow_id = input('flow_id');  //25
                $process_id = input('process_id');  //86
                $flow = Db::name('wf_flow') ->find($flow_id);
                //查询字段当前节点的表单字段信息
                //            if($flow['is_form_extend']==2){
                $form_field = Db::name('wf_form_field') ->where(['flow_id'=>$flow_id]) ->select();
                //添加当前节点内的选项数据
                $field_type = Db::name('wf_process') ->field('write,secret') ->find($process_id);
                foreach($field_type as $k=>$v) {
                    $field_type[$k] = explode(',', $v);
                }
                foreach($form_field as $k=>$v) {
                    if (in_array($v['id'], $field_type['write'])) {
                        $form_field[$k]['write'] = 'checked="true"';
                        $form_field[$k]['secret'] = 'disabled="true"';
                    } elseif (in_array($v['id'], $field_type['secret'])) {
                        $form_field[$k]['write'] = 'disabled="true"';
                        $form_field[$k]['secret'] = 'checked="true"';
                    }
                    if (!empty($form_field[$k]['content'])) {
                        $form_field[$k]['content'] = json_decode($v['content'], true);
                    }
                }
                //            }else{
                //                $form_field = Db::name('wf_form_field')->where(['form_extend_id' => $flow['form_extend_id']])->select();
                //            }
                foreach($form_field as $k=>$v) {
                    $form_field[$k]['is_form_extend'] = $flow['is_form_extend'];
                }
                //获取表单字段所有类型
                $option = Db::name('wf_field_type') ->select();
                //msg--类型，data--字段列表
                foreach($form_field as $k=>$v) {
                    $form_field[$k]['name'] = $v['source_table'].'*'.$v['name'];
                }
                return $this->success($option, $flow['is_form_extend'], $form_field);
            }
        }
        /**
        * 修改是否外接表单状态
        * @throws \think\Exception
        * @throws \think\exception\PDOException
        */
        public function save_switch() {
            if (request() ->isAjax()) {
                $flow_id = input('flow_id');
                $param['is_form_extend'] = input('type');
                $param['form_extend_id'] = input('form_extend_id');
                $res = Db::name('wf_flow') ->where('id', 'eq', $flow_id) ->update($param);
                return $this->success('选择成功', '', $res);
            }
        }
        /**
        * 获取有无外接表状态
        * @throws \think\db\exception\DataNotFoundException
        * @throws \think\db\exception\ModelNotFoundException
        * @throws \think\exception\DbException
        */
        public function get_switch() {
            if (request() ->isAjax()) {
                $flow_id = input('flow_id');
                $res = Db::name('wf_flow') ->find($flow_id);
                return $this->success('OK', '', $res);
            }
        }
        /**
        * 获取当前节点表单字段设置
        */
        public function field() {
            if (request() ->isAjax()) {
                $id = input('process_id');
                //节点基本信息
                $res = Db::name('wf_process') ->field('write,') ->find($id);
                //获取表单字段信息
                $form_field = Db::name('wf_form_field') ->whereIn('id', $res['write']) ->select();
                return $this->success('', '', $form_field);
            }
        }
        /**
        *新增表单字段
        */
        public function add_field() {
            if (request() ->isAjax()) {
                $param = $this->filter(input());
                $res = Db::name('wf_form_field') ->insert($param);
                return $this->success($res);
            }
        }
        /**
        * 获取人员列表
        */
        public function get_users() {
            if (request() ->isAjax()) {
                $process_id = input('id');
                $str = input('str');
                $list = Db::name('sys_user') ->field('id as value,username as name') ->select();
                $data = $this->default_select($process_id, $list, $str);
                return $this->success($data);
            }
        }
        /**
        * 获取角色列表
        */
        public function get_roles() {
            if (request() ->isAjax()) {
                $process_id = input('id');
                $str = input('str');
                $list = Db::name('sys_role') ->field('id as value,rolename as name') ->select();
                $data = $this->default_select($process_id, $list, $str);
                return $this->success($data);
            }
        }
        /**
        * 获取部门列表
        */
        public function get_depts() {
            if (request() ->isAjax()) {
                $process_id = input('id');
                $str = input('str');
                $list = Db::name('sys_dept') ->field('id as value,name as name') ->select();
                $data = $this->default_select($process_id, $list, $str);
                return $this->success($data);
            }
        }
        /**
        * 获取转出规则
        */
        public function get_con() {
            if (request() ->isAjax()) {
                $id = input('process_id');
                $process_to = Db::name('wf_process') ->field('process_to,out_param') ->find($id);
                //            $list = Db::name('wf_process')->whereIn('id', $process_to['process_to'])->field('id,option,desc')->select();
                $list = json_decode($process_to['out_param'], true);
                $data = array();
                foreach($list as $k=>$v) {
                    $v['option'] = $this->filter(explode("\n", $v['option'])); //切割成数组
                    foreach($v['option'] as $l=>$n) {
                        //准备一套=链接的条件方便数据处理
                        $replace = array('<>', '>', '<', '>=', '<=', '==', 'include', 'exclude');
                        $ns = str_replace($replace, '=', $n);
                        $field_id = str_replace("'", '', trim(substr($ns, 0, strrpos($ns, "="))));
                        $field = explode('*', $field_id); //[0]表名，[1]字段名
                        $field_name = $this->get_field_name($field);    //查询
                        $v['option'][$l] = array('value'=>str_replace(array("\r\n", "\r", "\n"), "", $n), 'html'=>str_replace(array("\r\n", "\r", "\n"), "", str_replace($field_id, $field_name['source_table'].'*'.$field_name['name'], $n)),);
                    }
                    $data[$v['id']] = $v;
                }
                $res = array('msg'=>'', 'code'=>200, 'data'=>$data,);
                return json($res);
            }
        }
        /**
        * 获取初始化样式
        */
        public function get_style() {
            if (request() ->isAjax()) {
                $id = input('process_id');
                $style = Db::name('wf_process') ->where('id', 'eq', $id) ->field('style') ->find() ['style'];
                $style = json_decode($style, true);
                return $this->success('', '', $style);
            }
        }
        /**
        * 保存节点属性变更
        */
        public function save_attribute() {
            if (request() ->isPost()) {
                $input = input();
                $param = array();    //--修改当前节点参数
                $param['process_name'] = $input['process_name'];                    //节点名
                $param['process_type'] = $input['process_type'];                    //节点类型
                if (isset($input['process_to'])) {
                    $param['process_to'] = implode(',', $input['process_to']);  //下游节点
                }
                $param['auto_person'] = $input['auto_person'];                      //审核权限预设
                $param['auto_unlock'] = isset($input['auto_unlock']) ? $input['auto_unlock'] : '0';  //是否可修改审核权限预设
                //            $param['auto_sponsor_uids'] = $input['auto_sponsor_uids'];          //指定主办人
                //            $param['auto_respon_uids'] = $input['auto_respon_uids'];            //指定经办人
                //            $param['auto_role_ids'] = $input['auto_role_ids'];                  //指定角色
                $param['range_user_ids'] = $input['range_user_ids'];                //授权人员
                $param['range_dept_ids'] = $input['range_dept_ids'];                //授权部门
                $param['range_role_ids'] = $input['range_role_ids'];                //授权角色
                $param['con_sign'] = $input['con_sign'];                            //会签方式
                $param['con_sign_vsb'] = $input['con_sign_vsb'];                    //是否可见
                $param['con_sign_back'] = $input['con_sign_back'];                  //回退方式
                $param['is_comment'] = isset($input['is_comment']) ? $input['is_comment'] : 0;                        //是否需要评论  1，是 |0，否
                $param['is_upload'] = isset($input['is_upload']) ? $input['is_upload'] : 0;                          //是否可以上传附件 1，是 |0，否
                $param['is_head'] = isset($input['is_head']) ? $input['is_head'] : 0;                              //授权部门时，是否为该部门主管 1，是 |0，否
                $param['write'] = isset($input['write']) ? implode(',', $this->match_element('data_', $input['write'], 'value', true)) : '';  //可写字段id串
                $param['secret'] = isset($input['secret']) ? implode(',', $this->match_element('data_', $input['secret'], 'value', true)) : ''; //保密字段id串
                //处理style参数
                $json = Db::name('wf_process') ->field('style') ->find($input['id']) ['style'];
                $array = json_decode($json, true);
                $style = $this->match_element('style_', $input, 'key', true);
                foreach($style as $k=>$v) {
                    $array[$k] = $v;    //没则添加，有则修改
                }
                $param['style'] = json_encode($array);   //样式数据
                //组装审批流表单条件
                $field_prm = array();
                $field_type = $this->match_element('field_type_', $input, 'key', true); //修改表单字段类型参数
                $field_content = $this->match_element('option_', $input, 'key', true);
                foreach($field_type as $key=>$val) {
                    $field_prm[$key]['field_type'] = $val;
                    if ($val != 1) {   //类型不为文本框
                        $field_prm[$key]['content'] = json_encode($field_content[$key]);
                    } elseif ($val == 1) {
                        $field_prm[$key]['content'] = '';
                    }
                }
                //转出规则条件处理
                $out_prm = array();
                foreach($input as $k=>$v) {
                    if (strpos($k, 'process_in_set_') !== false) {
                        $out_prm[str_replace('process_in_set_', '', $k) ]['id'] = str_replace('process_in_set_', '', $k);
                        $out_prm[str_replace('process_in_set_', '', $k) ]['option'] = $v;
                    } elseif (strpos($k, 'process_in_desc_') !== false) {
                        $out_prm[str_replace('process_in_desc_', '', $k) ]['desc'] = $v;
                    }
                }
                unset($out_prm['@a']);
                $param['out_param'] = json_encode($out_prm);  //当前节点写入出口规则
                foreach($field_prm as $k=>$v) {
                    Db::name('wf_form_field') ->where('id', $k) ->update($v);  //更新表单字段类型
                }
                $res = Db::name('wf_process') ->where('id', 'eq', $input['id']) ->update($param);  //更新节点表--当前节点
                if ($res == 1 || $res == 0) {
                    return $this->success('设置成功');
                } else {
                    return $this->error('设置失败');
                }
            }
        }
        /*********************************************************************流程页面**********************************************************************/
        /**
        *获取外接表单列表
        */
        public function get_form_extend() {
            if (request() ->isAjax()) {
                $flow_id = input('flow_id');
                $res = Db::name('wf_form_extend') ->field('id as value,china_name as name') ->where(['isdelete'=>0]) ->select();
                $basic = Db::name('wf_flow') ->field('form_extend_id') ->find($flow_id);
                foreach($res as $k=>$v) {
                    if ($v['value'] == $basic['form_extend_id']) {
                        $res[$k]['selected'] = true;
                    }
                }
                return $this->success('', '', $res);
            }
        }
        /**
        * 用于判断是否为外接表信息
        * @throws \think\db\exception\DataNotFoundException
        * @throws \think\db\exception\ModelNotFoundException
        * @throws \think\exception\DbException
        */
        public function judge_form_extend() {
            if (request() ->isAjax()) {
                $flow_id = input('flow_id');
                $data = Db::name('wf_flow') ->find($flow_id);
                if ($data['is_form_extend'] == 1) {
                    $form_extend = Db::name('wf_form_extend') ->find($data['form_extend_id']);
                    $data['value'] = $form_extend['controller'].'/'.$form_extend['action'];
                }
                return $this->success('成功提取信息', '', $data);
            }
        }
        /**
        *获取外接表单链接 /控制器和方法/
        */
        public function form_extend_detil() {
            if (request() ->isAjax()) {
                $form_id = request() ->post('form_id');
                $workflow_id = request() ->post('workflow_id');
                $data = Db::name('wf_form_extend') ->where(['isdelete'=>0]) ->find($form_id);
                $res = Db::name('wf_workflow') ->where(['isdelete'=>0, 'id'=>$workflow_id]) ->find();
                $data['form_extend'] = $res['form_extend'];
                $data['value'] = $data['controller'].'/'.$data['action'];
                return $this->success('抓取成功', '', $data);
            }
        }
        /**
        *获取审批表单
        */
        public function get_workflow_form_data() {
            if (request() ->isAjax()) {
                $workflow_id = input('worlflow_id');
                $field = $this->count_next_process($workflow_id);  //获取表单字段配置，字段数据，当前节点字段填写规则
                return $this->success('查询成功', '', $field);
            }
        }
        /**
        * 获取工作流详情页
        */
        public function get_detail_flow() {
            if (request() ->isAjax()) {
                $workflow_id = input('id');
                $data = $this->get_time_line($workflow_id);
                return $this->success('查询成功', '', $data);
            }
        }
        /**
        * 验证是否有正在使用该模版的流程
        */
        public function check_flow() {
            if (request() ->isAjax()) {
                $workflow_id = input('id');
                $audit_status = Db::name('wf_workflow') ->find($workflow_id) ['audit_status'];
                if (!empty($audit_status)) {
                    return $this->success($audit_status);
                }
                return $this->error('no');
            }
            return $this->error('no');
        }
        /**
        * 获取审批流列表页列表  --1，自发起 --2，待审核
        */
        public function get_workflow_list() {
            if (request() ->isAjax()) {
                $type = input('type');
                if ($type == 1) {
                    $where = array('wo.sponsor'=>$this->now_user, 'wo.isdelete'=>0);
                    $list = Db::name('wf_workflow') ->alias('wo') ->join('wf_flow fl', 'wo.flow_id=fl.id', 'left') ->join('wf_workprocess wp', 'wo.next_workprocess_id = wp.id', 'left') ->join('wf_process p', 'wp.process_id = p.id', 'left') ->join('sys_user u', 'u.id=wo.sponsor', 'left') ->field('wo.id as id,fl.name as name,wo.flow_id as flow_id,u.username as sponsor,wo.create_time as create_time,wo.audit_status as audit_status,p.process_name as process_name,p.con_sign as con_sign,wp.peoples as peoples,fl.is_form_extend,fl.form_extend_id,wo.form_extend form_extend') ->where($where) ->order('wo.id', 'asd') ->select();
                    //循环替换审核人名
                    foreach($list as $key=>$val) {
                        $peoples = Db::name('sys_user') ->whereIn('id', explode(',', $val['peoples'])) ->field('username') ->select();
                        foreach($peoples as $k=>$v) {
                            $peoples[$k] = $v['username'];
                        }
                        $list[$key]['peoples'] = implode(',', $peoples);
                    }
                } elseif ($type == 2) {
                    $where = array('examine_people'=>$this->now_user, 'status'=>0,  //未操作，需要操作
                    'isdelete'=>0);
                    //去重查询出所有待审核操作涉及的流程ID
                    $examineall = Db::name('wf_examine') ->where($where) ->distinct(true) ->field('workflow_id') ->order('workflow_id desc') ->select();
                    foreach($examineall as $k=>$v) {
                        $examineall[$k] = $v['workflow_id'];
                    }
                    //查询相关流程
                    $list = Db::name('wf_workflow') ->alias('wo') ->join('wf_flow fl', 'wo.flow_id=fl.id', 'left') ->join('wf_workprocess wp', 'wo.next_workprocess_id = wp.id', 'left') ->join('wf_process p', 'wp.process_id = p.id') ->join('sys_user u', 'u.id=wo.sponsor', 'left') ->field('wo.id as id,fl.name as name,wo.flow_id as flow_id,u.username as sponsor,wo.create_time as create_time,wo.audit_status as audit_status,p.process_name as process_name,p.con_sign as con_sign,wp.peoples as peoples,fl.is_form_extend,fl.form_extend_id,wo.form_extend form_extend') ->where(['audit_status'=>1, 'wo.isdelete'=>0]) ->whereIn('wo.id', $examineall)  //根据符合的流程id查询
                    ->order('wo.id', 'asd') ->select();
                    //循环替换审核人名
                    foreach($list as $key=>$val) {
                        $peoples = Db::name('sys_user') ->whereIn('id', explode(',', $val['peoples'])) ->field('username') ->select();
                        foreach($peoples as $k=>$v) {
                            $peoples[$k] = $v['username'];
                        }
                        $list[$key]['peoples'] = implode(',', $peoples);
                    }
                }
                foreach($list as $key=>$val) {
                    if (!empty($val['form_extend_id'])) {
                        $extend = Db::name('wf_form_extend') ->find($val['form_extend_id']);
                        if (!empty($extend)) {
                            $list[$key]['index'] = $extend['controller'].'/'.$extend['indexs'];
                            $list[$key]['add'] = $extend['controller'].'/'.$extend['adds'];
                            $list[$key]['edit'] = $extend['controller'].'/'.$extend['edits'];
                        }
                    }
                }
                $data = array('code'=>'200', 'msg'=>'请求成功', 'count'=>count($list), 'data'=>$list,);
                return $data;
            }
        }
        /**
        * 获取审批流模版下拉列表
        */
        public function get_flowlist() {
            if (request() ->isAjax()) {
                $res = Db::name('wf_flow') ->field('id as value,name as name') ->select();
                return $this->success('', '', $res);
            }
        }
        /**
        * 获取流程表单的配置
        */
        public function get_formconfig() {
            if (request() ->isAjax()) {
                $where = $this->filter(input()); //模版ID
                //获取模版表单
                $form_field = $this->get_flow_field($where);
                //获取附加限制
                $process = Db::name('wf_process') ->where(['flow_id'=>$where['flow_id'], 'process_type'=>'is_start']) ->field('is_comment,is_upload,flow_id') ->find();
                return $this->success($process, '', $form_field);
            }
        }
        /**
        * 拓印表单数据
        * @param $flow
        * @param $form_extend
        * @return array
        * @throws \think\db\exception\DataNotFoundException
        * @throws \think\db\exception\ModelNotFoundException
        * @throws \think\exception\DbException
        */
        public function get_formdata($flow, $form_extend) {
            $form_extends = Db::name('wf_form_extend') ->find($flow['form_extend_id']); //外接表名
            $field_list = Db::name('wf_flow') ->alias('f') ->join('wf_form_field ff', 'f.form_extend_id=ff.form_extend_id', 'inner') ->field('ff.id as id,ff.extend_field as extend_field') ->select();
            $array = array();
            foreach($field_list as $k=>$v) {
                $array[] = Db::name($form_extends['code_name']) ->where(['id'=>$form_extend]) ->field($v['extend_field']) ->find();
            }
            return $array;
        }
        /**
        * 发起流程
        */
        public function save_workflow() {
            if (request() ->isAjax()) {
                $put = file_get_contents('php://input');  //接收多维json
                $json = json_decode($put);
                $array = $this->object2array($json);
                if (empty($array)) {
                    $array = request() ->post();
                }
                $flow_id = $array['flow_id'];
                //查询模板信息进行分类处理
                $flow = Db::name('wf_flow') ->find($flow_id);
                //组装流程表数据
                $param = array();
                if ($flow['is_form_extend'] == 0) {
                    //查询字段信息
                    $formdata = $array;
                    foreach($formdata as $k=>$v) {
                        if ($v == 'on') {
                            $formdata[$k] = "true";
                        }
                    }
                    unset($formdata['content']);
                    unset($formdata['file']);
                    unset($formdata['flow_id']);
                } elseif ($flow['is_form_extend'] == 1) {
                    $param['form_extend'] = $array['form_extend'];
                    $formdata = $this->get_formdata($flow, $array['form_extend']);
                }
                $param['formdata'] = json_encode($formdata);  //存储表单数据
                $param['file_ids'] = implode(',', $this->match_element('file_ids', $array, 'key', true));
                $param['flow_id'] = $flow_id;              //存储表单数据
                $param['sponsor'] = $this->now_user;   //发起人
                $param['isdelete'] = 0;                    //是否删除
                $param['audit_status'] = 1;                //流程审批状态
                //写入流程表
                $workflow_res = Db::name('wf_workflow') ->insert($param);
                $workflow_id = Db::name('wf_workflow') ->getLastInsID();
                /*******************分配审批流数据节点(初始化)*********************/
                $process = Db::name('wf_process') ->where('flow_id', 'eq', $flow_id) ->select();  //查询模版节点信息
                $workprocess_param = array();
                foreach($process as $k=>$v) {
                    $workprocess_param[$k]['workflow_id'] = $workflow_id;            //工作流ID
                    $workprocess_param[$k]['process_id'] = $v['id'];                 //模版节点ID
                    $workprocess_param[$k]['con_sign'] = $v['con_sign'];             //节点审批模式
                    if ($v['process_type'] == 'is_start') {
                        $workprocess_param[$k]['node_status'] = 1;                   //节点审核状态
                    } else {
                        $workprocess_param[$k]['node_status'] = 0;
                    }
                    $workprocess_param[$k]['is_delegate'] = 0;                       //是否进行了委派
                    $workprocess_param[$k]['legate_users'] = '';                     //委派人员/人员集
                    $workprocess_param[$k]['legate_roles'] = '';                     //委派角色/角色集
                    $workprocess_param[$k]['legate_depts'] = '';                     //委派部门/部门集
                    $workprocess_param[$k]['isdelete'] = 0;
                }
                Db::name('wf_workprocess') ->insertAll($workprocess_param);  //入库
                /***************************循环插入审核人id**************************/
                foreach($process as $k=>$v) {
                    $where = array('workflow_id'=>$workflow_id, 'process_id'=>$v['id'],);
                    if ($v['process_type'] == 'is_start' || $v['process_type'] == 'is_end') {
                        $peoples = null;
                    } else {
                        $peoples = $this->seek_people($workflow_id, $v['id']); //查找审核人
                        Db::name('wf_workprocess') ->where($where) ->update(['peoples'=>(int)$peoples]);
                    }
                }
                /*******************获取起始流程节点信息和下一步流程节点信息*****************/
                $first_workprocess = $this->get_some_process($workflow_id, 'first');  //获取起始节点信息 一维数组
                $workprocess = $this->get_some_process($first_workprocess['id'], 'next');  //获取下一节点
                /****************回写起始节点和下一节点id到流程表以及下一节点的来源ID*****************/
                Db::name('wf_workflow') ->where('id', 'eq', $workflow_id) ->update(['first_workprocess_id'=>$first_workprocess['id'], 'next_workprocess_id'=>$workprocess['id']]);
                Db::name('wf_workprocess') ->where('id', 'eq', $workprocess['id']) ->update(['source_node'=>$first_workprocess['id']]);
                /*********************流程信息查询*******************/
                $workflow = Db::name('wf_workflow') ->find($workflow_id);
                /*********************写入消息表***********************/
                exit;
                $this->create_news($workflow, $workprocess, 'create');
                /*********************写入审核操作表*********************/
                $this->create_examine($workprocess);
                /*********************写入日志表*************************/
                $content = isset($array['content']) ? $array['content'] : '';
                $this->create_log($workflow, $content, 'create');
                return $this->success('成功发起流程', '', $workflow_res);
            }
        }
        /**
        * 审批操作  修改流程表状态 节点数据表状态
        */
        public function to_examine_workflow() {
            if (request() ->isAjax()) {
                $input = request() ->post();
                //获取审核人  ---当前审核人（登陆人）
                $user = $this->now_user;
                if (isset($input['file_ids'])) {
                    $file_ids = implode(',', $input['file_ids']);
                    //加入新的附件
                    $file = Db::name('wf_workflow') ->field('file_ids') ->find($input['workflow_id']);
                    Db::name('wf_workflow') ->where(['id'=>$input['workflow_id']]) ->update(['file_ids'=>$file['file_ids'].','.$file_ids]);
                }
                $workprocess = Db::name('wf_workprocess') ->find($input['next_workprocess_id']); //当前审核节点信息
                if ($workprocess['node_status'] == 1) {
                    return $this->error('您访问的流程已操作或已失效');
                }
                if ($input['type'] == 'next') {
                    $this->next($input);
                }
                if ($input['type'] == 'previous') {
                    $this->previous($input);
                }
                if ($input['type'] == 'first') {
                    $this->first($input);
                }
                return $this->success('操作成功');
            }
        }
        /**
        * 撤回
        */
        public function recall_work_flow() {
            if (request() ->isAjax()) {
                $workflow_id = input('id');
                $data = Db::name('wf_workflow') ->find($workflow_id);
                //1，结束所有审核操作
                Db::name('wf_examine') ->where(['workflow_id'=>$workflow_id]) ->update(['node_status'=>1, 'status'=>1]);
                //2，重置所有节点状态
                Db::name('wf_workprocess') ->where(['workflow_id'=>$workflow_id]) ->update(['node_status'=>0]);
                //3，重置流程状态为3 && 下一节点变为起始节点
                Db::name('wf_workflow') ->where(['id'=>$workflow_id]) ->update(['audit_status'=>4, 'next_workprocess_id'=>$data['first_workprocess_id']]);
                //写入操作日志
                $this->create_log($data, '', 'recall');
                return $this->success('成功撤回');
            }
        }
        /**
        * 获取编辑流程表单需要的默认值
        */
        public function get_workflow_default() {
            if (request() ->isAjax()) {
                $workflow_id = input('worlflow_id');
                $field = $this->count_next_process($workflow_id);  //获取表单字段配置，字段数据，当前节点字段填写规则
                return $this->success('查询成功', '', $field);
            }
        }
        /**
        * 删除附件
        */
        public function down_list_del() {
            if (request() ->isAjax()) {
                $id = input('id');
                $res = Db::name('wf_files') ->where(['id'=>$id]) ->update(['isdelete'=>1]);
                if ($res !== false) {
                    return $this->success('删除成功');
                } else {
                    return $this->error('删除失败');
                }
            }
        }
        /**
        * 重新发起
        */
        public function edit_workflow() {
            if (request() ->isAjax()) {
                $put = file_get_contents('php://input');  //接收多维json
                $json = json_decode($put);
                $input = $this->object2array($json);
                if (empty($input)) {
                    $input['workflow_id'] = request() ->post('workflow_id');
                }
                $workflow = Db::name('wf_workflow') ->where(['id'=>$input['workflow_id']]) ->find();
                //获取workflow_id 相关判断值
                $flow = Db::name('wf_flow') ->where(['id'=>$workflow['flow_id']]) ->find();
                //组装流程表数据
                $param = array();
                if ($flow['is_form_extend'] == 1) {
                    $param['form_extend'] = $workflow['form_extend'];
                    $array = $this->get_formdata($flow, $workflow['form_extend']);
                } else {
                    //处理修改后的附件
                    $field = $this->match_element('file_id', $input, 'key', true);
                    $param['file_ids'] = implode(',', $field);
                    //处理修改后的表单数据
                    $array = $this->match_element('field_', $input, 'key', false);
                    foreach($array as $k=>$v) {
                        if ($v == 'on') {
                            $array[$k] = "true";
                        }
                    }
                }
                $param['formdata'] = json_encode($array);  //存储表单数据
                $param['audit_status'] = 1;
                //修改初始节点状态
                Db::name('wf_workprocess') ->where(['id'=>$workflow['first_workprocess_id']]) ->update(['node_status'=>1]);
                //修改流程表
                Db::name('wf_workflow') ->where(['id'=>$input['workflow_id']]) ->update($param);
                //根据新数据重新验证下一节点的选择
                $workprocess = $this->get_some_process($workflow['first_workprocess_id'], 'next');
                //修改初始节点状态
                Db::name('wf_workprocess') ->where(['id'=>$workflow['first_workprocess_id']]) ->update(['node_status'=>1]);
                //回写下一审核节点
                Db::name('wf_workflow') ->where(['id'=>$input['workflow_id']]) ->update(['next_workprocess_id'=>$workprocess['id']]);
                /****************************流程信息查询*************************/
                $workflow = Db::name('wf_workflow') ->find($input['workflow_id']);
                /*********************写入消息表***********************/
                $this->create_news($workflow, $workprocess, 'create');
                /*********************写入审核操作表*********************/
                $this->create_examine($workprocess);
                /*********************写入日志表*************************/
                $content = isset($input['content']) ? $input['content'] : '';
                $this->create_log($workflow, $content, 'repeat');
                return $this->success('成功发起流程');
            }
        }
        /**
        *获取当前流程进度示意图数据
        */
        public function get_progress() {
            if (request() ->isAjax()) {
                $workflow_id = input('id');
                $list = Db::name('wf_workprocess') ->alias('wp') ->join('wf_process p', 'wp.process_id = p.id', 'left') ->where(['wp.workflow_id'=>$workflow_id]) ->field('wp.id,wp.process_id,wp.workflow_id,p.process_to,p.process_type,p.process_name title') ->select();
                foreach($list as $k=>$v) {
                    if (strpos($v['process_to'], ',')) {
                        $data = $this->get_some_process($v['id'], 'next'); //下一节点信息
                        $str_arr = explode(',', $v['process_to']);
                        foreach($str_arr as $key=>$val) {
                            if ($data['process_id'] != $val) {
                                foreach($list as $keys=>$vals) {
                                    if ($vals['process_id'] == $str_arr[$key]) {
                                        //                                    unset($list[$keys]); //清除list中不需要的分支
                                        $list[$k]['process_to'] = $data['process_id'];                                    //回写process_to
                                    }
                                }
                            };
                        }
                    }
                }
                //查询流程当前节点的ID
                $workflow = Db::name('wf_workflow') ->find($workflow_id);
                $now = '';
                $list = $this->level_order($list);  //递归加层排序
                foreach($list as $k=>$v) {
                    $res = Db::name('wf_log') ->alias('l') ->join('sys_user u', 'u.id=l.operator', 'left') ->where(['l.workflow_id'=>$v['workflow_id'], 'l.workprocess_id'=>$v['id']]) ->field('l.content,l.create_time,u.username') ->order('l.id', 'desc') ->find();
                    $list[$k]['content'] = $res['content'];
                    $list[$k]['create_time'] = $res['create_time'];
                    $list[$k]['username'] = $res['username'];
                    if ($v['id'] == $workflow['next_workprocess_id']) {
                        $now = $v['level']+1;
                    }
                    $list[$k]['level'] = $v['level']+1;
                }
                if ($workflow['audit_status'] == 2) {
                    $now = count($list);
                }
                $array = array('list'=>$list, 'now'=>$now,);
                return $this->success('查询成功', '', $array);
            }
        }
        /*********************************************************************杂乱方法*********************************************************************/
        /**
        * 按需返回节点信息
        * @param $id_str
        * @param $type   first  back  next  last
        * @return array|bool|false|\PDOStatement|string|\think\Collection|\think\Model|null
        * @throws \think\db\exception\DataNotFoundException
        * @throws \think\db\exception\ModelNotFoundException
        * @throws \think\exception\DbException
        */
        public function get_some_process($id_str, $type) {
            $workflow_id = $id_str;
            $workprocess_id = $id_str;
            $data = array();
            switch ($type) {
                case 'first':
                    //查询起始节点 --条件为$workflow_id
                    $data = Db::name('wf_workflow') ->alias('wf') ->join('wf_workprocess wp', 'wf.id = wp.workflow_id', 'left') ->join('wf_process p', 'wp.process_id=p.id') ->where(['wp.workflow_id'=>$workflow_id, 'p.process_type'=>'is_start']) ->field('wp.*') ->find();
                break;
                case 'back':
                    //查询上个节点 --获取的是$workprocess_id
                    $back_workprocess_id = Db::name('wf_workprocess') ->where(['id'=>$workprocess_id]) ->field('source_node') ->find() ['source_node'];
                    $data = Db::name('wf_workprocess') ->where(['id'=>$back_workprocess_id]) ->find();
                break;
                case 'next':
                    //查询下个节点 --获取的是$workprocess_id
                    $select = Db::name('wf_workprocess') ->field('workflow_id') ->find($workprocess_id);
                    $next_process_id = $this->judge_next_choice($workprocess_id);
                    $data = Db::name('wf_workprocess') ->where(['workflow_id'=>$select['workflow_id'], 'process_id'=>$next_process_id]) ->find();
                break;
                case 'last':
                    //查询末尾节点 --获取的是$workflow_id
                    $data = Db::name('wf_workflow') ->alias('wf') ->join('wf_workprocess wp', 'wf.id = wp.workflow_id', 'left') ->join('wf_process p', 'wp.process_id=p.id') ->where(['wf.id'=>$workflow_id, 'p.process_type'=>'is_end']) ->field('wp.*') ->find();
                break;
            }
            return $data;
        }
        /**
        * 根据流程表单中的值自动识别下一步并且返回下一步模板节点ID
        * @param $workprocess_id  当前工作流节点
        * @return bool|int|mixed|string  下一节点ID或者false（异常）
        * @throws \think\db\exception\DataNotFoundException
        * @throws \think\db\exception\ModelNotFoundException
        * @throws \think\exception\DbException
        */
        public function judge_next_choice($workprocess_id = 606) {
            $retutn_id = '';
            $workprocess_data = Db::name('wf_workprocess') ->alias('wp') ->join('wf_process p', 'p.id = wp.process_id', 'left') ->where(['wp.id'=>$workprocess_id]) ->field(['p.process_to,p.flow_id,wp.workflow_id,p.out_param'])  //获取下级节点列表列表，流程模板ID，流程ID
            ->find();
            //        $process = Db::name('wf_process')->whereIn('id',explode(',',$workprocess_data['process_to']))->select(); //下一节点的模板节点ID
            $process = json_decode($workprocess_data['out_param'], true);
            if (count($process) <= 1) {
                $num = end($process) ['id'];
                return $num;  //下级节点只有一个时直接返回
            }
            $array = array();
            /**
            * 这里没有处理好↓
            * 导致无法多条件判断 没有and和or的判断
            */
            foreach($process as $key=>$val) {
                $reg = "/(AND|OR)+?/";  //两个空格之间是数字的正则
                preg_match($reg, $val['option'], $out);
                $array[$val['id']] = preg_split($reg, $val['option']);
            }
            //        echo '<pre>';
            //        print_r($process);
            //        echo '</pre>';
            //        echo '<pre>';
            //        print_r($array);
            //        echo '</pre>';
            //        exit;
            /**
            * 这里没有处理好↑
            */
            $flow = Db::name('wf_flow') ->find($workprocess_data['flow_id']);
            $workdata = Db::name('wf_workflow') ->find($workprocess_data['workflow_id']); //获取当前节点在流程的form表单信息 （分歧点，自表差流程表，外表读数据）
            if ($flow['is_form_extend'] == 1) {
                $form_datas = Db::name($flow['table_name']) ->find($workdata['form_extend']); //根据外接表单的表名和数据ID获取数据
                $user_data = Db::name('sys_user') ->find($workdata['sponsor']); //获取发起人信息
                $re_array = Db::name('wf_form_field') ->where(['isdelete'=>0, 'flow_id'=>$workprocess_data['flow_id']]) ->field('id,field_name,source_table') ->select();
                $form_data = array();
                foreach($form_datas as $key=>$val) {
                    foreach($re_array as $k=>$v) {
                        if ($v['field_name'] == $key && $v['source_table'] == $flow['table_name']) {
                            $form_data[$v['id']] = $val;
                        }
                    }
                }
                foreach($user_data as $key=>$val) {
                    foreach($re_array as $k=>$v) {
                        if ($v['field_name'] == $key && $v['source_table'] == 'sys_user') {
                            $form_data[$v['id']] = $val;
                        }
                    }
                }
            } else {
                $form_data = json_decode($workdata['formdata'], true);  //--这是表单json
                $form_data = $this->match_element('field_', $form_data, 'key', true);
            }
            $default = array();  //--将空值设为默认
            foreach($array as $k=>$v) {
                if (empty($v[0])) {
                    $default = $k;
                    continue;
                }
                foreach($v as $key=>$val) {
                    $warray = $this->filter(explode("'", $val));
                    if ($flow['is_form_extend'] == 1) {
                        $param = explode('*', $warray[1]);
                        $field_id = Db::name('wf_form_field') ->where(['source_table'=>$param[0], 'field_name'=>$param[1]]) ->find() ['id'];
                        $warray[1] = $field_id;
                        $wk = $warray;
                    } else {
                        $wk = $this->match_element('data_', $warray, 'value', true);
                    }
                    //对比当前节点判断的字段 在填写报表数据里是否有对应值，有的话取出对比
                    if (array_key_exists($wk[1], $form_data)) {
                        $field = Db::name('wf_form_field') ->field('content') ->find($wk[1]);
                        if (!empty($field['content'])) {
                            $form_data_field = json_decode($field['content'], true);
                            $res = $this->val_compare($warray, $form_data_field[$form_data[$wk[1]]]);
                        } else {
                            $res = $this->val_compare($warray, $form_data[$wk[1]]);
                        }
                        if ($res == 1) {
                            $retutn_id = $k;
                        }
                    } else {
                        return false;  //需要填写审核用的必要数据短缺（数据异常）
                    }
                }
                if (!empty($retutn_id)) {
                    break;
                }
            }
            if (empty($retutn_id)) {
                $retutn_id = $default; //没有匹配到则取默认节点
            }
            return $retutn_id;
        }
        /**
        * 比较选择返回
        * @param $array
        * @param $str
        */
        public function val_compare($array, $str) {
            switch ($array[2]) {
                case ' = ':
                    if (end($array) == $str) {
                        return 1;
                    } else {
                        return 0;
                    };
                break;
                case ' <> ':
                    if (end($array) <> $str) {
                        return 1;
                    } else {
                        return 0;
                    };
                break;
                case ' > ':
                    if (intval($str) >intval(end($array))) {
                        return 1;
                    } else {
                        return 0;
                    };
                break;
                case ' < ':
                    if (intval($str) <intval(end($array))) {
                        return 1;
                    } else {
                        return 0;
                    };
                break;
                case ' >= ':
                    if (intval($str) >= intval(end($array))) {
                        return 1;
                    } else {
                        return 0;
                    };
                break;
                case ' <= ':
                    if (intval($str) <= intval(end($array))) {
                        return 1;
                    } else {
                        return 0;
                    };
                break;
                case ' include ':
                    if (strstr(end($array), $str) === false) {
                        return 0;
                    } else {
                        return 1;
                    };
                break;
                case ' exclude ':
                    if (strstr(end($array), $str) === false) {
                        return 1;
                    } else {
                        return 0;
                    };
                break;
            }
        }
        /**
        * 根据流程ID查询接下来要审核的节点字段信息
        */
        public function count_next_process($workflow_id) {
            //补充操作id
            $ex_id = Db::name('wf_examine') ->where(['examine_people'=>$this->now_user, 'status'=>0]) ->find();
            $workflow = Db::name('wf_workflow') ->find($workflow_id);  //选中流程信息   $workflow['formdata'] 当前表单数据
            $workflow['ex_id'] = $ex_id['id'];
            $workprocess = Db::name('wf_workprocess') ->find($workflow['next_workprocess_id']); //查找下一需审核节点信息 当前模型节点ID $workflow['next_workprocess_id'];
            //获取附加限制
            $process = Db::name('wf_process') ->where(['flow_id'=>$workflow['flow_id'], 'id'=>$workprocess['process_id']]) ->field('is_comment,is_upload') ->find();
            $workflow['is_comment'] = $process['is_comment'];
            $workflow['is_upload'] = $process['is_upload'];
            $form_fields = $this->get_flow_field(['flow_id'=>$workflow['flow_id']]);  //表单字段信息查询
            $process = Db::name('wf_process') ->find($workprocess['process_id']);
            $form_config = explode(',', $process['write']); //当前节点的表单展示规则
            $downlist = $this->get_down_list($workflow_id);
            $res = array('msg'=>$workflow, 'data'=>$form_fields,            //表单字段配置
            'form_data'=>json_decode($workflow['formdata'], true),  //表单数据  field_+id
            'form_config'=>$form_config,      //当前节点可写配置
            'process'=>$process,              //节点配置
            'downlist'=>$downlist,);
            return $res;
        }
        /**
        * 获取字段名字
        * @param string|array $id
        * @return mixed
        * @throws \think\db\exception\DataNotFoundException
        * @throws \think\db\exception\ModelNotFoundException
        * @throws \think\exception\DbException
        */
        public function get_field_name($id) {
            if (is_array($id)) {
                $res = Db::name('wf_form_field') ->where(['source_table'=>$id[0], 'field_name'=>$id[1]]) ->find();
            } else {
                $res = Db::name('wf_form_field') ->field('field_name') ->where('id', 'eq', $id) ->find() ['field_name'];
            }
            return $res;
        }
        /**
        * 获取上级节点
        */
        public function get_up($id) {
            $flow_id = Db::name('wf_process') ->field('flow_id') ->find($id) ['flow_id'];
            $process_list = Db::name('wf_process') ->where('flow_id', 'eq', $flow_id) ->field('id,process_to') ->select();
            $data = array();
            foreach($process_list as $k=>$v) {
                if (in_array($id, [$v['process_to']])) {
                    $data[] = $v;
                }
            }
            return $data;
        }
        /**
        *  打回上一步
        *
        *1，修改工作流的当前节点
        *2，并且修改上一个节点的状态
        *3，修改审核操作表当前节点的所有相关审核状态(使其作废) node_status=1  |status=1
        *4，重新发布上一步审核操作需求
        *5，如果回到原点则修改工作流状态
        *
        */
        public function previous($data) {
            $content = isset($data['content']) ? $data['content'] : '';
            $workprocess = Db::name('wf_workprocess') ->find($data['next_workprocess_id']); //当前节点信息
            $workflow = Db::name('wf_workflow') ->find($workprocess['workflow_id']); //当前流程信息
            //先修改当前操作记录的操作类型
            Db::name('wf_examine') ->where(['workflow_id'=>$data['workflow_id'], 'workprocess_id'=>$data['next_workprocess_id']]) ->update(['node_status'=>1, 'status'=>1]); //修改当前节点的所有相关审核
            //重新发布新的审核操作-通知-日志
            $workprocess2 = $this->get_some_process($workprocess['id'], 'back'); //查询上一个节点
            //判断上一步节点是否为原点
            $process2 = Db::name('wf_process') ->find($workprocess2['process_id']);
            if ($process2['process_type'] == 'is_start') {
                Db::name('wf_workprocess') ->where('id', 'eq', $workprocess2['id']) ->update(['node_status'=>0]);  //修改上一个节点状态
                Db::name('wf_workflow') ->where('id', 'eq', $data['workflow_id']) ->update(['next_workprocess_id'=>$workprocess2['id'], 'audit_status'=>3]); //回退到起始结点，（关闭）
                $this->create_log($workflow, $content, 'repulse'); //写入日志--当前操作日志
                $this->create_news($workflow, $workprocess2, 'repulse'); //写入消息--通知发起人
            } else {
                Db::name('wf_workprocess') ->where('id', 'eq', $workprocess2['id']) ->update(['node_status'=>0]);  //修改上一个节点状态
                Db::name('wf_workflow') ->where('id', 'eq', $data['workflow_id']) ->update(['next_workprocess_id'=>$workprocess2['id']]); //只修改下一个审核的节点ID
                $this->create_examine($workprocess2);
                $this->create_log($workflow, $content, 'repulse'); //写入日志--当前操作日志
                $this->create_news($workflow, $workprocess2, 'adopt'); //写入消息--通知下一节点的所有审核人
            }
        }
        /**
        *打回原点
        */
        public function first($data) {
            $content = isset($data['content']) ? $data['content'] : '';
            $workflow = Db::name('wf_workflow') ->find($data['workflow_id']); //当前流程信息
            $first_workprocess = $this->get_some_process($data['workflow_id'], 'first');
            $notwhere = array();
            array_push($notwhere, $first_workprocess['id']);
            Db::name('wf_examine') ->where(['workflow_id'=>$data['workflow_id'], 'workprocess_id'=>$data['next_workprocess_id']]) ->update(['node_status'=>1, 'status'=>1]); //修改当前节点的所有相关审核
            Db::name('wf_workprocess') ->where(['workflow_id'=>$data['workflow_id']]) ->whereNotIn('id', $notwhere) ->update(['node_status'=>0]);
            //发布-通知-日志
            Db::name('wf_workflow') ->where('id', 'eq', $data['workflow_id']) ->update(['next_workprocess_id'=>$first_workprocess['id'], 'audit_status'=>3]); //回退到起始结点，（关闭）
            $this->create_log($workflow, $content, 'repulse'); //写入日志--当前操作日志
            $this->create_news($workflow, $first_workprocess, 'repulse'); //写入消息--通知发起人
        }
        /**
        *审批通过
        */
        public function next($data) {
            $content = isset($data['content']) ? $data['content'] : '';
            $workprocess = Db::name('wf_workprocess') ->find($data['next_workprocess_id']); //当前节点信息
            $process = Db::name('wf_process') ->find($workprocess['process_id']); //当前模型节点
            $workflow = Db::name('wf_workflow') ->find($workprocess['workflow_id']);
            //查询流程当前审核情况
            $con_sign = $process['con_sign'];     //审核类型
            if ($con_sign == 2 || $con_sign == 1) {              //非会签（指定单人，直接审核）或者 单一会审
                //修改对应的操作记录
                Db::name('wf_workprocess') ->where(['id'=>$data['next_workprocess_id']]) ->update(['node_status'=>1]);   //先修改当前审批节点状态
                Db::name('wf_examine') ->where(['workflow_id'=>$workprocess['workflow_id'], 'workprocess_id'=>$workprocess['id'], 'status'=>0]) ->update(['status'=>1, 'node_status'=>1]);  //标识操作记录为已经操作
                //查询下一节点的节点类型
                $workprocess2 = $this->get_some_process($workprocess['id'], 'next');  //获取下一节点
                $process2 = Db::name('wf_process') ->find($workprocess2['process_id']);
                if ($process2['process_type'] == 'is_end') { //没有下一级
                    Db::name('wf_workflow') ->where('id', $data['workflow_id']) ->update(['audit_status'=>2, 'next_workprocess_id'=>'']);
                    $this->create_log($workflow, $content, 'end'); //写入日志--当前操作日志
                    $this->create_news($workflow, $workprocess, 'end'); //写入消息--通知发起人流程已完结并且关闭
                } else { //有下一级
                    Db::name('wf_workflow') ->where('id', $data['workflow_id']) ->update(['audit_status'=>1, 'next_workprocess_id'=>$workprocess2['id']]); //修改工作流审核进度到下一节点
                    //生成后续操作记录
                    $this->create_examine($workprocess2);
                    $this->create_log($workflow, $content, 'adopt'); //写入日志--当前操作日志
                    $this->create_news($workflow, $workprocess2, 'adopt'); //写入消息--通知下一节点的所有审核人
                }
            } elseif ($con_sign == 3) {     //会审--全部通过
                //查询当前节点未审核人数
                $where = array('workflow_id'=>$data['workflow_id'], 'workprocess_id'=>$data['next_workprocess_id'], 'status'=>0);
                $list = Db::name('wf_examine') ->where($where) ->select();
                $ex_where = array('workflow_id'=>$workprocess['workflow_id'], 'workprocess_id'=>$workprocess['id'], 'status'=>0, 'examine_people'=>$this->now_user,);
                if (count($list) == 1) { //说明这是最后一条审核,需要修改工作流表和节点数据表
                    //修改对应的操作记录
                    Db::name('wf_workprocess') ->where(['id'=>$data['next_workprocess_id']]) ->update(['node_status'=>1]);   //先修改当前审批节点状态
                    Db::name('wf_examine') ->where($ex_where) ->update(['status'=>1, 'node_status'=>1]);  //标识操作记录为已经操作
                    $workprocess2 = $this->get_some_process($workprocess['id'], 'next');  //获取下一节点
                    //查询下一节点的节点类型
                    $process2 = Db::name('wf_process') ->find($workprocess2['process_id']);
                    if ($process2['process_type'] == 'is_end') { //没有下一级
                        Db::name('wf_workflow') ->where('id', $data['workflow_id']) ->update(['audit_status'=>2, 'next_workprocess_id'=>'']); //该流程完全通过
                        $this->create_log($workflow, $content, 'end'); //写入日志--当前操作日志
                        $this->create_news($workflow, $workprocess, 'end'); //写入消息--通知发起人流程已完结并且关闭
                    } else { //有下一级
                        Db::name('wf_workflow') ->where('id', $data['workflow_id']) ->update(['audit_status'=>1, 'next_workprocess_id'=>$workprocess2['id']]); //修改流程审核进度到下一节点
                        $this->create_examine($workprocess2);                    //发布下一节点的审核需求到每个审核人
                        $this->create_log($workflow, $content, 'adopt'); //写入日志--当前操作日志
                        $this->create_news($workflow, $workprocess2, 'adopt'); //写入消息--通知下一节点的所有审核人
                    }
                } else {  //不需要修改工作流表和节点数据表
                    Db::name('wf_examine') ->where($ex_where) ->update(['status'=>1, 'node_status'=>1]);  //标识操作记录为已经操作
                    $this->create_log($workflow, $content, 'adopt'); //写入日志--当前操作日志
                }
            };
            Db::name('wf_workprocess') ->where('id', 'eq', $workprocess2['id']) ->update(['source_node'=>$workprocess['id']]);
        }
        /**
        * 创建新的待审核操作信息  workflow_id工作流ID  |  workprocess_id操作节点ID  |  examine_people操作人ID  |  con_sign节点模式  |  audit_status当前被操作节点的状态   / status当前操作状态
        * @param  $param (需要操作的节点信息数组)
        */
        public function create_examine($param) {
            $examine_param = array();
            foreach(explode(',', $param['peoples']) as $k=>$v) {
                $examine_param[] = array('workflow_id'=>$param['workflow_id'], 'workprocess_id'=>$param['id'], 'examine_people'=>$v, 'con_sign'=>$param['con_sign'], 'node_status'=>$param['node_status'], 'status'=>0, 'isdelete'=>0,);
            };
            Db::name('wf_examine') ->insertAll($examine_param);
        }
        /**
        * 创建消息
        * @param $workflow -- 工作流数组
        * @param $workprocess -- 需要发布消息的节点数组
        * @param $type
        */
        public function create_news($workflow, $workprocess, $type) {
            $news_param = array();
            $name = Db::name('sys_user') ->find($workflow['sponsor']) ['username'];
            $flow_name = Db::name('wf_flow') ->find($workflow['flow_id']) ['name'];
            if ($type == 'repulse') {
                $news_param[] = array('isdelete'=>0,                          //是否删除
                'workflow_id'=>$workflow['id'],         //流程ID
                'flow_id'=>$workflow['flow_id'],        //流程模版ID
                'workprocess_id'=>$workprocess['id'],   //流程节点ID
                'operator'=>$this->now_user,        //消息发起人ID
                'notice_people'=>$workflow['sponsor'],                    //消息接受人ID
                'is_read'=>0,                           //是否已读
                'content'=>'您发起的流程被打回，请修正后重新发起',);
            } elseif ($type == 'end') {
                $news_param[] = array('isdelete'=>0,                          //是否删除
                'workflow_id'=>$workflow['id'],         //流程ID
                'flow_id'=>$workflow['flow_id'],        //流程模版ID
                'workprocess_id'=>$workprocess['id'],   //流程节点ID
                'operator'=>$this->now_user,        //消息发起人ID
                'notice_people'=>$workflow['sponsor'],                    //消息接受人ID
                'is_read'=>0,                           //是否已读
                'content'=>'您发起的流程已审核通过，请点击查看',);
            } else {
                foreach(explode(',', $workprocess['peoples']) as $k=>$v) {
                    $msg = "";
                    switch ($type) {
                        case 'create':
                            $msg = $name.'发起的'.$flow_name.'流程需要您审批';
                        break;
                        case 'adopt':
                            $msg = $name.'发起的'.$flow_name.'流程需要您审核';
                        break;
                        case 'repeat':
                            $msg = $name.'重新发起的'.$flow_name.'流程需要您审核';
                        break;
                    }
                    $news_param[] = array('isdelete'=>0,                          //是否删除
                    'workflow_id'=>$workflow['id'],         //流程ID
                    'flow_id'=>$workflow['flow_id'],        //流程模版ID
                    'workprocess_id'=>$workprocess['id'],   //流程节点ID
                    'operator'=>$this->now_user,        //消息发起人ID
                    'notice_people'=>$v,                    //消息接受人ID
                    'is_read'=>0,                           //是否已读
                    'content'=>$msg);
                }
            }
            Db::name('wf_news') ->insertAll($news_param);
        }
        /**
        * 流程操作日志
        * @param $data --工作流数组
        * @param $content -- 留言评论
        * @param $type
        */
        public function create_log($data, $content = '', $type) {
            $log_param = array('isdelete'=>0,                              //是否删除
            'workflow_id'=>$data['id'],                 //流程ID
            'flow_id'=>$data['flow_id'],                //流程模版ID
            'workprocess_id'=>$data['next_workprocess_id'],       //流程节点ID
            'operator'=>$this->now_user,    //操作人ID
            );
            $msg = "";
            $flow_name = Db::name('wf_flow') ->find($data['flow_id']) ['name'];
            $username = session('username');
            switch ($type) {
                case 'create':
                    $msg = $username.'发起了'.$flow_name.'审批流';
                    $log_param['type'] = 'create';
                    $log_param['workprocess_id'] = $data['first_workprocess_id']; //创建的时候是对起始节点操作
                break;
                case 'adopt':
                    $log_param['type'] = 'adopt';
                    $msg = $username.'审核通过'.$flow_name.'审批流'.$data['next_workprocess_id'].'节点';
                break;
                case 'repulse':
                    $log_param['type'] = 'repulse';
                    $msg = $username.'打回了'.$flow_name.'审批流'.$data['next_workprocess_id'].'节点';
                break;
                case 'end':
                    $log_param['type'] = 'end';
                    $msg = $username.'结束了'.$flow_name.'审批流';
                break;
                case 'recall':
                    $log_param['type'] = 'recall';
                    $msg = $username.'撤回了'.$flow_name.'审批流';
                break;
                case 'repeat':
                    $log_param['type'] = 'repeat';
                    $msg = $username.'重发了'.$flow_name.'审批流';
                break;
            }
            $log_param['msg'] = $msg;
            $log_param['content'] = $content;
            Db::name('wf_log') ->insert($log_param);
        }
        /**
        * 获取工作流时间线
        * @param $id --工作流id
        */
        public function get_time_line($id) {
            $where = array('l.workflow_id'=>$id, 'l.isdelete'=>0);
            //根据日志链操作表进行查询
            $list = Db::name('wf_log') ->alias('l') ->join('sys_user u', 'l.operator = u.id', 'left') ->where($where) ->field('l.id as id,l.create_time as time,l.type as type,l.msg as msg,l.content as content,u.name as username') ->select();
            return $list;
        }
        /**
        * 表单字段信息查询
        * @param $where ['flow_id'=>value]  流程模版ID条件数组
        * @return bool|false|\PDOStatement|string|\think\Collection
        * @throws \think\db\exception\DataNotFoundException
        * @throws \think\db\exception\ModelNotFoundException
        * @throws \think\exception\DbException
        */
        public function get_flow_field($where) {
            $form_field = Db::name('wf_form_field') ->where($where) ->select();
            foreach($form_field as $k=>$v) {
                if (!empty($form_field[$k]['content'])) {
                    $form_field[$k]['content'] = json_decode($v['content'], true);
                }
            }
            return $form_field;
        }
        /**
        * 审核鉴权方法，用来寻找节点的审核人
        * @param $workflow_id  审批流ID
        * @param $process_id   当前节点ID
        * @param string $type 查询控制 now=当前节点  next=下一节点ID
        *
        */
        public function seek_people($workflow_id, $process_id) {
            $seek_people = "";
            $data = Db::name('wf_process') ->find($process_id);
            switch ($data['auto_person']) {
                case 1:   //不自动选人
                    if ($data['is_head'] == 1) { //判断节点选择了部门主管
                        $dept_arr = Db::name('sys_user') ->where(['is_executive'=>1]) ->wherein('dep_id', $data['range_dept_ids']) ->field('id') ->select();
                    } elseif ($data['is_head'] == 0) {
                        $dept_arr = Db::name('sys_user') ->wherein('dep_id', $data['range_dept_ids']) ->field('id') ->select();
                    }
                    foreach($dept_arr as $k=>$v) {
                        $dept_arr[$k] = $v['id'];
                    }
                    //根据角色id去查找对应的人员集合
                    $role_arr = Db::name('sys_user') ->wherein('roleid', $data['range_role_ids']) ->field('id') ->select();
                    foreach($role_arr as $k=>$v) {
                        $role_arr[$k] = $v['id'];
                    }
                    $user_arr = explode(',', $data['range_user_ids']);
                    $d = array_keys(array_flip($dept_arr) +array_flip($role_arr) +array_flip($user_arr));
                    $seek_people = implode(',', $this->filter($d));
                break;
                case 2:   //发起人
                    $seek_people = Db::name('wf_workflow') ->field('sponsor') ->find($workflow_id) ['sponsor'];
                break;
                case 3:   //发起人的部门主管
                    $sponsor = Db::name('wf_workflow') ->field('sponsor') ->find($workflow_id) ['sponsor'];
                    $dept_id = Db::name('sys_user') ->where('id', 'eq', $sponsor) ->find() ['dep_id'];
                    $dw = array('dep_id'=>$dept_id, 'is_executive'=>1);
                    $dept_data = Db::name('sys_user') ->where($dw) ->field('id') ->find();
                    $seek_people = $dept_data['id'];
                break;
            }
            return $seek_people;
        }
        /**
        * 鉴权规则
        * @param $res
        */
        public function seek_people_config($res) {
            $seek_people = "";
            $data = Db::name('wf_process') ->find($res['process_id']);
            switch ($data['auto_person']) {
                case 1:   //不自动选人
                    if ($data['is_head'] == 1) { //判断节点选择了部门主管
                        $dept_arr = Db::name('sys_user') ->where('roleid', 'eq', 3) ->wherein('dep_id', $data['range_dept_ids']) ->field('id') ->select();
                    } elseif ($data['is_head'] == 0) {
                        $dept_arr = Db::name('sys_user') ->wherein('dep_id', $data['range_dept_ids']) ->field('id') ->select();
                    }
                    foreach($dept_arr as $k=>$v) {
                        $dept_arr[$k] = $v['id'];
                    }
                    //根据角色id去查找对应的人员集合
                    $role_arr = Db::name('sys_user') ->wherein('roleid', $data['range_role_ids']) ->field('id') ->select();
                    foreach($role_arr as $k=>$v) {
                        $role_arr[$k] = $v['id'];
                    }
                    $user_arr = explode(',', $data['range_user_ids']);
                    $d = array_keys(array_flip($dept_arr) +array_flip($role_arr) +array_flip($user_arr));
                    $seek_people = implode(',', $this->filter($d));
                break;
                case 2:   //发起人
                    $seek_people = Db::name('wf_workflow') ->field('sponsor') ->find($res['workflow_id']) ['sponsor'];
                break;
                case 3:   //发起人的部门主管
                    $sponsor = Db::name('wf_workflow') ->field('sponsor') ->find($res['workflow_id']) ['sponsor'];
                    $dept = Db::name('sys_user') ->where('id', 'eq', $sponsor) ->find() ['dep_id'];
                    $dw = array('dep_id'=>$dept, 'roleid'=>'3'   //假设角色3为部门主管
                    );
                    $dept_data = Db::name('sys_user') ->where($dw) ->field('id') ->find();
                    $seek_people = $dept_data['id'];
                break;
            }
            return $seek_people;
        }
        /**
        * 递归节点层级level排序,起始依据为process_type==is_start 排序对比字段为process_to(id包含关系)
        * @param $array
        * @param $level
        * @param $data
        * @return mixed
        */
        public function level_order($array) {
            static $level = 0;
            static $data = array();
            if (count($array) >0) {
                foreach($array as $k=>$v) {
                    if ($v['process_type'] == 'is_start') {
                        $v['level'] = $level;
                        $data[$level] = $v;
                        $level++;
                        unset($array[$k]);
                        return $this->level_order($array);
                    } else {
                        foreach($data as $key=>$val) {
                            if (in_array($v['process_id'], explode(',', $val['process_to']))) {
                                $v['level'] = $level;
                                $data[$level] = $v;
                                $level++;
                                unset($array[$k]);
                                return $this->level_order($array);
                            }
                        }
                    }
                }
            } else {
                return $data;
            }
            return $data;
        }
        /**
        * 正则去除开头和结尾的单引号
        * @param $str
        * @return int
        */
        function remove_quote(&$str) {
            if (preg_match("/^\'/", $str)) {
                $str = substr($str, 1, strlen($str) -1);
            }
            //判断字符串是否以'''结束
            if (preg_match("/\'$/", $str)) {
                $str = substr($str, 0, strlen($str) -1);;
            }
            $str = intval($str);
            return $str;
        }
        /**
        * 匹配返回符合的数组元素
        * @param $str     匹配规则
        * @param $array   操作数组
        * @param $rely    匹配凭借  key|value
        * @param $type    是否清除key中多余字符串
        */
        public function match_element($str, $array, $rely, $type = false) {
            $data = array();
            foreach($array as $k=>$v) {
                if ($v != '') {
                    if ($rely == 'key') {
                        if (strpos($k, $str) !== false) {
                            if ($type == false) {
                                $data[$k] = $v;
                            } elseif ($type == true) {
                                $data[str_replace($str, '', $k) ] = $v;
                            }
                        }
                    } elseif ($rely == 'value') {
                        if (strpos($v, $str) !== false) {
                            if ($type == false) {
                                $data[$k] = $v;
                            } elseif ($type == true) {
                                $data[$k] = str_replace($str, '', $v);
                            }
                        }
                    }
                }
            }
            return $data;
        }
        /**
        *增加xmselect的选择记忆项
        * @param $id     节点ID
        * @param $array  待处理数组
        * @param $str    对比字段
        */
        public function default_select($id, $array, $str) {
            $basic = Db::name('wf_process') ->field($str) ->find($id);
            foreach($basic as $k=>$v) {
                $basic[$k] = explode(',', $v);
            }
            foreach($array as $k=>$v) {
                if (in_array($v['value'], $basic[$str])) {
                    $array[$k]['selected'] = true;
                }
            }
            return $array;
        }
        /**
        * * 根据数组条件修改json中，键的对应值
        * $arr1  条件数组
        * json   需替换的字段
        */
        public function handle_json($arr, $json) {
            $array = json_decode($json, true);  //转换为数组
            foreach($arr as $k=>$v) {
                if (isset($array[$k])) {
                    $array[$k] = $v;
                }
            }
            return json_encode($array);
        }
        /**
        * 据说适用于10W高并发场景得对象转数组方法
        * @param $object
        * @return mixed
        */
        public function object2array(&$object) {
            $object = json_decode(json_encode($object), true);
            return $object;
        }
        /**
        * 过滤空元素
        */
        public function filter($array) {
            foreach($array as $k=>$v) {
                $v = trim($v);
                if (empty($v)) {
                    if ($v !== '0') {
                        unset($array[$k]);
                    }
                }
            }
            return $array;
        }
        /**
        * layui分片上传   概念性方法，暂不可用
        */
        public function layui_part_upload() {
            $status = 1;
            //上传文件要保存的路径
            $fname = sprintf('/tmp/%s.%s', $_POST['fileName'], $_POST['fileExt']);
            $data = file_get_contents($_FILES['file']['tmp_name']);
            if ($_POST['page'] == 1) {
                file_put_contents($fname, $data);
            } else {
                //其余文件追加到文件末尾
                file_put_contents($fname, $data, FILE_APPEND);
            }
            //最后一片文件
            if ($_POST['totalPage'] == $_POST['page']) {
                $status = 2;
            }
            //返回上传状态
            $res = ['status'=>$status, 'downUrl'=>"http://localhost/data.dat"];
            echo json_encode($res);
        }
        /**
        * 获取附件列表
        * @param $workflow_id
        * @return bool|false|\PDOStatement|string|\think\Collection
        * @throws \think\db\exception\DataNotFoundException
        * @throws \think\db\exception\ModelNotFoundException
        * @throws \think\exception\DbException
        */
        public function get_down_list($workflow_id) {
            $file_ids = explode(',', Db::name('wf_workflow') ->field('file_ids') ->find($workflow_id) ['file_ids']);
            //获取附件列表
            $list = Db::name('wf_files') ->alias('f') ->join('sys_user u', 'u.id = f.user_id', 'left') ->field('f.id as id,f.name as name,f.new_name as new_name,f.format as format,f.folder as folder,f.complete_path as complete_path,u.username as username') ->where(['f.isdelete'=>0]) ->whereIn('f.id', $file_ids) ->select();
            return $list;
        }
        /**
        * layui 整体上传
        */
        public function layui_upload() {
            $file = request() ->file('file'); // 获取上传的文件
            if ($file == null) {
                exit (json_encode(array('code'=>1, 'msg'=>'未上传文件')));
            }
            // 获取文件后缀
            $temp = explode(".", $_FILES["file"]["name"]);          //原文件名|文件类型
            $extension = end($temp);
            $path = ROOT_PATH.'public'.'/'.'upload'.'/'.'tmp';                  //D:\phpstudy_pro\WWW\OA_object\public\upload\tmp
            $info = $file->move($path);                                            // 移动文件到指定目录 没有则创建
            $fname = $info->getSaveName();
            $temps = explode('/', $fname);
            $folder = array_shift($temps);                               //获取时间文件夹
            $new_name = explode(".", end($temps)) [0];           //新的文件名
            $complete_path = $path.'/'.$fname;                                 //本地完整路径
            $relative_path = 'public/upload/tmp/'.$folder.'/'.$temps[0];               //相对地址  --以后会有用？直觉？
            $param = array('user_id'=>$this->now_user,  //归属人
            'name'=>$temp[0],  //原文件名
            'format'=>$temp[1], //文件格式
            'folder'=>$folder,   //所在本地文件夹
            'new_name'=>$new_name, //系统内分配的文件名
            'complete_path'=>$relative_path, //相对路径
            );
            //信息存入数据库返回ID进行绑定
            Db::name('wf_files') ->insert($param);
            $file_id = Db::name('wf_files') ->getLastInsID();
            $param['file_id'] = $file_id;
            return $this->success('成功', '', $param);
        }
        /**
        * 下载
        * @throws \think\db\exception\DataNotFoundException
        * @throws \think\db\exception\ModelNotFoundException
        * @throws \think\exception\DbException
        */
        public function download() {
            $id = input('id');
            $url = Db::name('wf_files') ->find($id);
            $complete_path = ROOT_PATH.$url['complete_path'];
            // 检查文件是否存在
            if (!file_exists($complete_path)) {
                $this->error('文件未找到');
            } else {
                // 打开文件
                $file1 = fopen($complete_path, "r");
                // 输入文件标签
                Header("Content-type: application/octet-stream");
                Header("Accept-Ranges: bytes");
                Header("Accept-Length:".filesize($complete_path));
                header('Content-Disposition: attachment; filename='.$url['name'].'.'.$url['format']);
                header('Content-Type: application/octet-stream; name='.$url['name'].'.'.$url['format']);
                ob_clean();     // 重点！！！可以清除文件中多余的路径名以及解决乱码的问题
                flush();        // 重点！！！！：
                //输出文件内容
                //读取文件内容并直接输出到浏览器
                $content = fread($file1, filesize($complete_path));
                echo $content;
                exit ();
            }
        }
        /*******************************内部调用增删改的方法接口*****************************/
        /**
        * auto创建工作流
        * @param $id  创建工作流参数  --关联数据ID
        * @param $controller  创建工作流参数  --控制器名
        * @param string $array  提交新建流程的原始数据，没有就不传
        * @throws \think\Exception
        * @throws \think\db\exception\DataNotFoundException
        * @throws \think\db\exception\ModelNotFoundException
        * @throws \think\exception\DbException
        * @throws \think\exception\PDOException
        */
        public function create_workflow($id, $controller, $array = '') {
            $flow = Db::name('wf_flow') ->where(['controller'=>$controller]) ->find();
            $param = array('form_extend'=>$id, 'flow_id'=>$flow['id'], 'sponsor'=>$this->now_user,       //发起人
            'isdelete'=>0,                    //是否删除
            'audit_status'=>1,                //流程审批状态
            );
            //写入流程表
            Db::name('wf_workflow') ->insert($param);
            $workflow_id = Db::name('wf_workflow') ->getLastInsID();
            /*******************分配审批流数据节点(初始化)*********************/
            $process = Db::name('wf_process') ->where('flow_id', 'eq', $param['flow_id']) ->select();  //查询模版节点信息
            $workprocess_param = array();
            foreach($process as $k=>$v) {
                $workprocess_param[$k]['workflow_id'] = $workflow_id;            //工作流ID
                $workprocess_param[$k]['process_id'] = $v['id'];                 //模版节点ID
                $workprocess_param[$k]['con_sign'] = $v['con_sign'];             //节点审批模式
                if ($v['process_type'] == 'is_start') {
                    $workprocess_param[$k]['node_status'] = 1;                   //节点审核状态
                } else {
                    $workprocess_param[$k]['node_status'] = 0;
                }
                $workprocess_param[$k]['is_delegate'] = 0;                       //是否进行了委派
                $workprocess_param[$k]['legate_users'] = '';                     //委派人员/人员集
                $workprocess_param[$k]['legate_roles'] = '';                     //委派角色/角色集
                $workprocess_param[$k]['legate_depts'] = '';                     //委派部门/部门集
                $workprocess_param[$k]['isdelete'] = 0;
            }
            Db::name('wf_workprocess') ->insertAll($workprocess_param);  //入库
            /***************************循环插入审核人id**************************/
            foreach($process as $k=>$v) {
                $where = array('workflow_id'=>$workflow_id, 'process_id'=>$v['id'],);
                if ($v['process_type'] == 'is_start' || $v['process_type'] == 'is_end') {
                    $peoples = null;
                } else {
                    $peoples = $this->seek_people($workflow_id, $v['id']); //查找审核人
                    Db::name('wf_workprocess') ->where($where) ->update(['peoples'=>(int)$peoples]);
                }
            }
            /*******************获取起始流程节点信息和下一步流程节点信息*****************/
            $first_workprocess = $this->get_some_process($workflow_id, 'first');  //获取起始节点信息 一维数组
            $workprocess = $this->get_some_process($first_workprocess['id'], 'next');  //获取下一节点
            /****************回写起始节点和下一节点id到流程表以及下一节点的来源ID*****************/
            Db::name('wf_workflow') ->where('id', 'eq', $workflow_id) ->update(['first_workprocess_id'=>$first_workprocess['id'], 'next_workprocess_id'=>$workprocess['id']]);
            Db::name('wf_workprocess') ->where('id', 'eq', $workprocess['id']) ->update(['source_node'=>$first_workprocess['id']]);
            /*********************流程信息查询*******************/
            $workflow = Db::name('wf_workflow') ->find($workflow_id);
            /*********************写入消息表***********************/
            $this->create_news($workflow, $workprocess, 'create');
            /*********************写入审核操作表*********************/
            $this->create_examine($workprocess);
            /*********************写入日志表*************************/
            $content = isset($array['content']) ? $array['content'] : '';
            $this->create_log($workflow, $content, 'create');
            return $workflow_id;
        }
        /**
        * auto重新发起表单
        * @param $workflow  即时查询的需要修改的流程
        * @param $input  修改的原始数据，可以为空
        * @return bool
        * @throws \think\Exception
        * @throws \think\db\exception\DataNotFoundException
        * @throws \think\db\exception\ModelNotFoundException
        * @throws \think\exception\DbException
        * @throws \think\exception\PDOException
        */
        public function repeat_work_flow($id, $controller, $input = '') {
            $flow_id = Db::name('wf_flow') ->where(['controller'=>$controller]) ->find() ['id'];
            $params = array('form_extend'=>$id, 'flow_id'=>$flow_id,);
            $workflow = Db::name('wf_workflow') ->where($params) ->find();
            $param['audit_status'] = 1;
            //修改初始节点状态
            Db::name('wf_workprocess') ->where(['id'=>$workflow['first_workprocess_id']]) ->update(['node_status'=>1]);
            //修改流程表
            Db::name('wf_workflow') ->where(['id'=>$workflow['id']]) ->update($param);
            //根据新数据重新验证下一节点的选择
            $workprocess = $this->get_some_process($workflow['first_workprocess_id'], 'next');
            //修改初始节点状态
            Db::name('wf_workprocess') ->where(['id'=>$workflow['first_workprocess_id']]) ->update(['node_status'=>1]);
            //回写下一审核节点
            Db::name('wf_workflow') ->where(['id'=>$workflow['id']]) ->update(['next_workprocess_id'=>$workprocess['id']]);
            /****************************流程信息查询*************************/
            $workflows = Db::name('wf_workflow') ->find($workflow['id']);
            /*********************写入消息表***********************/
            $this->create_news($workflows, $workprocess, 'create');
            /*********************写入审核操作表*********************/
            $this->create_examine($workprocess);
            /*********************写入日志表*************************/
            $content = isset($input['content']) ? $input['content'] : '';
            $this->create_log($workflows, $content, 'repeat');
            if ($workflows['audit_status'] == 1) {
                return true;
            } else {
                return false;
            };
        }
        /**
        * 流程删除方法
        */
        public function auto_delect_workflow($id, $controller) {
            $flow_id = Db::name('ht_formtype') ->where(['controller'=>$controller]) ->find() ['flow_id'];
            $param = array('form_extend'=>$id, 'flow_id'=>$flow_id,);
            $workflow = Db::name('wf_workflow') ->where($param) ->find();
            $bool = $this->deleteaction($workflow['id']);
            return $bool;
        }
        /**
        * 删除流程方法
        * @param $workflow_id  需要流程ID
        * @return bool
        */
        public function deleteaction($workflow_id) {
            try {
                //删除对应操作表
                Db::name('wf_examine') ->where('workflow_id', 'eq', $workflow_id) ->update(['isdelete'=>1]);
                //删除相关节点数据
                Db::name('wf_workprocess') ->where('workflow_id', 'eq', $workflow_id) ->update(['isdelete'=>1]);
                //删除审批流模版
                Db::name('wf_workflow') ->where('id', 'eq', $workflow_id) ->update(['isdelete'=>1]);
                Db::commit();
                $bool = true;
            }
            catch(\Exception $e) {
                Db::rollback();
                $bool = false;
            }
            return $bool;
        }
        /*******************************************list列表*****************************************/
        /**
        * 各个报表列表页获取数据的方法
        */
        public function get_list() {
            if (request() ->isAjax()) {
                $params = request() ->param();
                $type = $params['type'];
                $controller = '当前控制器';
                $param = array();
                if (isset($params['page']) && $params['page'] != '') {
                    $page = $params['page'];
                }
                if (isset($params['limit']) && $params['limit'] != '') {
                    $limit = $params['limit'];
                }
                if (isset($params['id']) && $params['id'] != '') {
                    $param['wo.id'] = $params['id'];
                }
                if (isset($params['name']) && $params['name'] != '') {
                    $param['fl.name'] = ['like', "%".$params['name']."%"];
                }
                $data = array();
                $mdeol = new Workflowajax();
                $data = $mdeol->get_list_data($param, $page, $limit, $type, $controller);
                return $data;
            }
        }
        /**
        * 获取列表数据
        * @param $param         其他参数
        * @param $page          页数
        * @param $limit         每页数量
        * @param $type         当前状态（1-流程列表，2-审批列表）
        * @param $controller   当前控制器名
        * @return array
        * @throws \think\db\exception\DataNotFoundException
        * @throws \think\db\exception\ModelNotFoundException
        * @throws \think\exception\DbException
        */
        public function get_list_data($param, $page, $limit, $type, $controller) {
            $workflwo = new Workflowajax();
            $param['wo.isdelete'] = 0;
            if ($type == 1) {
                $param['wo.sponsor'] = session('id');
                $data = $workflwo->get_workflow_lists($controller, $param, $page, $limit);
            } elseif ($type = 2) {
                $data = $workflwo->get_check_list($controller, $param, $page, $limit);
            }
            if ($data) {
                $ret['data'] = $data;
                $ret['code'] = 0;
                $ret['msg'] = '获取数据成功';
            } else {
                $ret['data'] = '';
                $ret['code'] = -1;
                $ret['msg'] = '获取数据为空';
            }
            return $data;
        }
        /**
        * 获取列表方法
        * @return array
        * @throws \think\db\exception\DataNotFoundException
        * @throws \think\db\exception\ModelNotFoundException
        * @throws \think\exception\DbException
        */
        public function get_workflow_lists($controller, $param, $page, $limit) {
            $param['fl.controller'] = $controller;
            $list = Db::name('wf_workflow') ->alias('wo') ->join('wf_flow fl', 'wo.flow_id=fl.id', 'left') ->join('wf_workprocess wp', 'wo.next_workprocess_id = wp.id', 'left') ->join('wf_process p', 'wp.process_id = p.id', 'left') ->join('sys_user u', 'u.id=wo.sponsor', 'left') ->field('fl.controller,wo.id as id,fl.name as name,wo.flow_id as flow_id,u.name as sponsor,wo.create_time as create_time,wo.audit_status as audit_status,p.process_name as process_name,p.con_sign as con_sign,wp.peoples as peoples,fl.is_form_extend,fl.form_extend_id,wo.form_extend form_extend') ->where($param) ->order('wo.id', 'asd') ->paginate($limit, false, ['page'=>$page]);
            $list = $list->toArray();
            //循环替换审核人名
            foreach($list['data'] as $key=>$val) {
                $peoples = Db::name('sys_user') ->whereIn('id', explode(',', $val['peoples'])) ->field('name') ->select();
                foreach($peoples as $k=>$v) {
                    $peoples[$k] = $v['name'];
                }
                $list['data'][$key]['peoples'] = implode(',', $peoples);
            }
            $data = array('code'=>'200', 'msg'=>'请求成功', 'count'=>$list['total'], 'data'=>$list['data'],);
            return $data;
        }
        /**
        *获取待审核列表
        */
        public function get_check_list($controller, $param, $page, $limit) {
            $where['isdelete'] = 0;
            $roleid = session('roleid');
            if ($param['state'] != 2) {
                $where['examine_people'] = $this->now_user;
            }
            if (isset($param['state'])) {
                if ($param['state'] == 0) {
                    $where['status'] = 0; //待审核
                } elseif ($param['state'] == 1) {
                    $where['status'] = 1;
                }
            }
            //去重查询出所有待审核操作涉及的流程ID
            $examineall = Db::name('wf_examine') ->where($where) ->distinct(true) ->field('workflow_id') ->order('workflow_id desc') ->select();
            foreach($examineall as $k=>$v) {
                $examineall[$k] = $v['workflow_id'];
            }
            if (!empty($controller)) {
                $param['fl.controller'] = $controller;
            }
            unset($param['state']);
            //查询相关流程
            $list = Db::name('wf_workflow') ->alias('wo') ->join('wf_flow fl', 'wo.flow_id=fl.id', 'left') ->join('wf_workprocess wp', 'wo.next_workprocess_id = wp.id', 'left') ->join('wf_process p', 'wp.process_id = p.id', 'left') ->join('sys_user u', 'u.id=wo.sponsor', 'left') ->field('fl.controller,wo.id as id,fl.name as name,wo.flow_id as flow_id,u.name as sponsor,wo.create_time as create_time,wo.audit_status as audit_status,p.process_name as process_name,p.con_sign as con_sign,wp.peoples as peoples,fl.is_form_extend,fl.form_extend_id,wo.form_extend form_extend') ->where($param) ->whereIn('wo.id', $examineall)  //根据符合的流程id查询
            ->order('wo.id', 'asd') ->paginate($limit, false, ['page'=>$page]);
            $list = $list->toArray();
            //循环替换审核人名
            foreach($list['data'] as $key=>$val) {
                $peoples = Db::name('sys_user') ->whereIn('id', explode(',', $val['peoples'])) ->field('name') ->select();
                if (!in_array($this->now_user, explode(',', $val['peoples']))) {
                    $list['data'][$key]['is_qualifications'] = 1;
                } else {
                    $list['data'][$key]['is_qualifications'] = 0;
                }
                foreach($peoples as $k=>$v) {
                    $peoples[$k] = $v['name'];
                }
                $list['data'][$key]['peoples'] = implode(',', $peoples);
            }
            foreach($list['data'] as $key=>$val) {
                $list['data'][$key]['index'] = $val['controller'].'/details';
            }
            $data = array('code'=>'200', 'msg'=>'请求成功', 'count'=>$list['total'], 'data'=>$list['data'],);
            return $data;
        }
        /***************************************************************************************/
    }
    